package com.sunyard.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sunyard.constant.ErrMessageConst;
import com.sunyard.constant.StatusConstant;
import com.sunyard.dal.bo.PaginationBO;
import com.sunyard.dal.bo.role.RoleAuditBO;
import com.sunyard.dal.bo.role.RoleAuditChangeQueryBO;
import com.sunyard.dal.bo.role.RoleAuditQueryBO;
import com.sunyard.dal.dto.RoleCopyDTO;
import com.sunyard.dal.dto.RoleCopyExportDTO;
import com.sunyard.dal.entity.Operator;
import com.sunyard.dal.entity.Popedom;
import com.sunyard.dal.entity.Role;
import com.sunyard.dal.entity.RoleCopy;
import com.sunyard.dal.entity.RolePopedom;
import com.sunyard.dal.mapper.OperatorMapper;
import com.sunyard.dal.mapper.OrganizationMapper;
import com.sunyard.dal.mapper.PopedomMapper;
import com.sunyard.dal.mapper.RoleCopyMapper;
import com.sunyard.dal.mapper.RoleMapper;
import com.sunyard.manage.service.OperatorLogService;
import com.sunyard.manage.service.RoleAuditService;
import com.sunyard.redisUtil.RedisUtil;
import com.sunyard.redisUtil.RedisUtils;
import com.sunyard.utils.DtoUtils;
import com.sunyard.utils.ExcelOutput;
import com.sunyard.utils.Response.BaseResult;
import com.sunyard.utils.Response.GetResult;
import com.sunyard.utils.Response.HeaderResult;
import com.sunyard.utils.TokenUtil;
import com.sunyard.utils.manage.DataGrid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * @author jiy.fang
 * @ClassName RoleAuditServiceImpl
 * @Description description
 * @date 2019/7/25 8:54
 */
@Service
@Slf4j
public class RoleAuditServiceImpl implements RoleAuditService {

    @Autowired
    private RoleCopyMapper roleCopyMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private PopedomMapper popedomMapper;

    @Autowired
    private OperatorMapper operatorMapper;

    @Autowired
    private OperatorLogService operatorLogService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${admin.name}")
    private String admin;

    @Value("${auditor.name}")
    private String auditor;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * @Description: 分页查询角色审核信息
     * @Author: jiy.fang
     * @Date: 2019/7/25 8:56
     */
    @Override
    public DataGrid<RoleCopyDTO> queryRoleListAuditByPage(HttpServletRequest request, PaginationBO<RoleAuditQueryBO> queryBO) throws Exception {
        RoleAuditQueryBO roleAuditQueryBO = queryBO.getParams();
        log.info("角色审核记录查询入参：{}", JSON.toJSONString(roleAuditQueryBO));
        String orgId = TokenUtil.getOrgId(request.getHeader("token"));
        String opId = TokenUtil.getOpId(request.getHeader("token"));
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("orgId", orgId);
        queryMap.put("opId", opId);
        queryMap.put("roleName", roleAuditQueryBO.getRoleName());
        queryMap.put("auditFlag", roleAuditQueryBO.getAuditFlag());
        queryMap.put("auditType", roleAuditQueryBO.getAuditType());
        queryMap.put("includeSubOrg", roleAuditQueryBO.getIncludeSubOrg());
        //获取当前机构及下属机构id集合
        List<String> orgIds = getListOrgIds(orgId);
        orgIds.add(orgId);
        queryMap.put("list", orgIds);
        //设置分页信息
        PageHelper.startPage(queryBO.getPageNo(), queryBO.getPageSize());
        //执行查询 查询当前登录用户能审核的记录
        List<RoleCopyDTO> list = roleCopyMapper.getRoleCopyListByPage(queryMap);
        //取分页信息
        PageInfo<RoleCopyDTO> pageInfo = new PageInfo<>(list);
        //设置返回结果
        DataGrid<RoleCopyDTO> dataGrid = new DataGrid<>();
        Long total = pageInfo.getTotal();
        dataGrid.setTotal(total.intValue());
        dataGrid.setRows(list);
        return dataGrid;
    }

    @Override
    public void roleAuditExport(HttpServletResponse response, RoleAuditQueryBO roleAuditQueryBO, HttpServletRequest request) {
        try {
            String opId = TokenUtil.getOpId(request.getHeader("token"));
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            String opName = TokenUtil.getOpName(request.getHeader("token"));
            operatorLogService.insert("角色审核导出", "角色审核导出", "1", opId, opName, orgId);
            // 执行查询
            List<RoleCopyExportDTO> list = roleCopyMapper.roleAuditExport(roleAuditQueryBO);
            if (list == null || list.isEmpty()) {
                throw new RuntimeException("无数据无需导出");
            }
            String title = "角色审核导出" + Math.random() + ".xls";
            String[] headers = new String[]{"审核流水号", "审核操作", "审核状态", "角色名称", "申请日期", "操作人","审核人", "审核理由"};

            List<Object[]> dataList;
            dataList = list.stream().map(roleCopy -> {
                Object[] obj = new Object[headers.length];
                obj[0] = roleCopy.getAuditId();
                obj[1] = roleCopy.getAuditType();
                obj[2] = roleCopy.getAuditFlag();
                obj[3] = roleCopy.getRoleName();
                obj[4] = roleCopy.getCreateTime();
                obj[5] = roleCopy.getCreateOp();
                obj[6] = roleCopy.getAuditOp();
                obj[7] = roleCopy.getRoleRemark();
                return obj;
            }).collect(toList());
            OutputStream out = null;
            // 防止中文乱码
            String headStr = "attachment; filename=\"" + new String(title.getBytes("gb2312"), "ISO8859-1") + "\"";
            response.setContentType("octets/stream");
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition", headStr);
            out = response.getOutputStream();
            ExcelOutput ex = new ExcelOutput(title, headers, dataList);
            ex.export(out);
            log.info("角色审核导出");
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            HeaderResult.setFailHeader(request, response, e.getMessage());
        }
    }

    /**
     * @Description: 角色审核操作
     * @Author: jiy.fang
     * @Date: 2019/7/25 10:50
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult<GetResult> roleAudit(HttpServletRequest request, RoleAuditBO roleAuditBO) throws Exception {
        String opId = TokenUtil.getOpId(request.getHeader("token"));
        String orgId = TokenUtil.getOrgId(request.getHeader("token"));
        String opName = TokenUtil.getOpName(request.getHeader("token"));
        //获取需要审核的记录
        RoleCopy roleCopy = roleCopyMapper.getRoleCopyByAuditId(roleAuditBO.getAuditId());
        if(null==roleCopy){
            return GetResult.getResultFail("该审核记录不存在！");
        }
        //获取审核前的记录
        //Role roleBefore = roleMapper.getAuditBefore(roleAuditBO.getAuditId());
        Role roleBefore = roleMapper.getRoleByRoleId(roleCopy.getRoleId());

        //定义日志信息
        String operationDesc = "用户" + opName + "审核了：" + roleBefore.getRoleName();

        //判断当前登录用户是否是指定审核人
        if (!opId.equals(roleCopy.getAuditor())) {
            return GetResult.getResultFail("当前用户没有审核权限！");
        }
        if (!StatusConstant.AUDIT_FLAG_DEFAULT.equals(roleCopy.getAuditFlag())) {
            return GetResult.getResultFail("该审核记录已审核！");
        }
        //修改审核记录表
        roleCopy.setAuditOp(opId);
        roleCopy.setAuditFlag(roleAuditBO.getAuditFlag());
        roleCopy.setAuditDesc(roleAuditBO.getAuditDesc());
        roleCopy.setEntityRecord(JSON.toJSONString(roleBefore));
        roleCopyMapper.updateRoleCopy(roleCopy);
        log.info("更新角色审核表记录，审核编号={}", roleAuditBO.getAuditId());
        //如果审核结果为不通过，直接返回
        if (StatusConstant.AUDIT_FLAG_FAIL.equals(roleAuditBO.getAuditFlag()) || StatusConstant.AUDIT_FLAG_DEFAULT.equals(roleAuditBO.getAuditFlag())) {
            if (StatusConstant.AUDIT_TYPE_ROLECONFIGPOPEDOM.equals(roleCopy.getAuditType())) {
                //删除角色权限分配审核临时表
                popedomMapper.deleteRolePopedomTep(roleCopy.getRoleId());
            }
            log.info("角色审核不通过，审核编号={}，角色编号={}", roleCopy.getAuditId(), roleCopy.getRoleId());
            //添加详细日志
            operatorLogService.insert(operationDesc, "角色审核", "1", opId, opName, orgId);
            return GetResult.getResultSuccess("审核成功！");
        }
        //修改角色主表信息
        Role role = new Role();
        DtoUtils.cloneBeanToBean(role, roleCopy);
        if (StatusConstant.AUDIT_TYPE_ADD.equals(roleCopy.getAuditType())) {
            role.setRoleState("0");
            int result = roleMapper.insert(role);
            if (result > 0) {
                //将审核成功的角色在权限临时表的权限 加到 正式表
                addRolePopedom(role, roleCopy);
            }
            log.info("添加角色通过审核，将审核表数据添加到角色主表，审核编号={}，角色编号={}", roleCopy.getAuditId(), roleCopy.getRoleId());
        } else if (StatusConstant.AUDIT_TYPE_UPDATE.equals(roleCopy.getAuditType())) {
            roleMapper.updateRole(role);
            redisUtils.clearPopedomListByRoleId(role.getRoleId());
            //获取最新分配的权限
            List<RolePopedom> newRolePopedomList = popedomMapper.findTepRolePopedomListByRoleId(role.getRoleId(),
                    roleCopy.getAuditId());
            //删除机构权限表原有的权限 删除临时表权限数据
            popedomMapper.deleteRolePopedom(role.getRoleId());
            //更新机构权限表
            if (!newRolePopedomList.isEmpty()) {
                popedomMapper.insertRolePopedom(newRolePopedomList);
            }
            log.info("角色权限分配通过审核，审核编号={}，机构编号={}", roleCopy.getAuditId(), roleCopy.getOrgId());
            //获取该角色下所属权限,并被迫登出
            List<Operator> operatorList = operatorMapper.getListOperatorByroleId(roleCopy.getRoleId());
            for (Operator operator1 : operatorList) {
                disableLogout(operator1);
            }
            log.info("修改角色通过审核，将审核表数据添加到角色主表，审核编号={}，角色编号={}", roleCopy.getAuditId(), roleCopy.getRoleId());
        } else if (StatusConstant.AUDIT_TYPE_DELETE.equals(roleCopy.getAuditType())) {
            redisUtils.clearPopedomListByRoleId(role.getRoleId());
            roleMapper.deleteRole(role);
            //删除角色权限表原有的权限
            popedomMapper.deleteRolePopedom(role.getRoleId());
        } else {
            return GetResult.getResultFail("该审核记录状态错误！");
        }
        //添加详细日志
        operatorLogService.insert(operationDesc, "角色审核", "1", opId, opName, orgId);
        //返回处理结果
        return GetResult.getResultSuccess("审核成功！");
    }

    @Override
    public Map<Object, Object> queryRoleRecordChange(RoleAuditChangeQueryBO changeQueryBO) {
        RoleCopyDTO roleCopyDTO = roleCopyMapper.getRoleCopyDTOByAuditId(changeQueryBO.getAuditId());
        Role role = JSON.parseObject(roleCopyDTO.getEntityRecord(), Role.class);
        Map<Object, Object> orgComparisonMap = new HashMap<>();
        //  添加角色审核对比
        if (roleCopyDTO.getAuditType() == 0) {
            orgComparisonMap.put("roleAudit", roleCopyDTO);
        }
        //  角色删除审核对比
        if (roleCopyDTO.getAuditType() == 1) {
            if (roleCopyDTO.getAuditFlag() == 0) {
                orgComparisonMap.put("role", role);
            }
            if (roleCopyDTO.getAuditFlag() == 1) {
                orgComparisonMap.put("role", roleCopyDTO);
            }
            if (roleCopyDTO.getAuditFlag() == 2) {
                orgComparisonMap.put("role", role);
            }
        }
        //  角色修改审核对比
        if (roleCopyDTO.getAuditType() == 2) {
            orgComparisonMap.put("roleAudit", roleCopyDTO);
            orgComparisonMap.put("role", role);
        }
        return orgComparisonMap;
    }

    /**
     * @Description: 角色权限变化
     * @Author: jiy.fang
     * @Date: 2019/9/16 15:43
     */
    @Override
    public Map<String, List<String>> queryRolePopedomChange(RoleAuditChangeQueryBO changeQueryBO) {

        RoleCopyDTO roleCopyDTO = roleCopyMapper.getRoleCopyDTOByAuditId(changeQueryBO.getAuditId());

        //查询修改前的权限
        List<Popedom> oldPopedom;
        List<Integer> auditSns = popedomMapper.getRolePopedomTmpByRoleId(roleCopyDTO.getRoleId());
        if (auditSns.size() <= 1) {
            //说明第一次做权限配置，直接去主表查询现有的权限
            //不展示默认权限 --by zihui
            oldPopedom = popedomMapper.getRolePopedomWithoutDefaultByRoleId(roleCopyDTO.getRoleId());
        } else {
            //说明已经做过权限分配，在tmp表查询修改前权限
            //不展示默认权限 --by zihui
            oldPopedom = popedomMapper.getRolePopedomByIdAndSn(roleCopyDTO.getRoleId(),
                    auditSns.get(1));
        }
        List<Popedom> newPopedom = popedomMapper.getRolePopedomByIdAndSn(roleCopyDTO.getRoleId(),
                roleCopyDTO.getAuditSn());
        List<String> addPopedom = new ArrayList<>();
        List<String> deletePopedom = new ArrayList<>();
        if (null != oldPopedom && !oldPopedom.isEmpty()) {
            for (Popedom popedom : oldPopedom) {
                if (!newPopedom.contains(popedom)) {
                    deletePopedom.add(popedom.getPopedomName());
                }
            }
        }
        if (null != oldPopedom && !oldPopedom.isEmpty()) {
            for (Popedom popedom : newPopedom) {
                if (!oldPopedom.contains(popedom)) {
                    addPopedom.add(popedom.getPopedomName());
                }
            }
        }

        Map<String, List<String>> popedomMap = new HashMap<>();
        popedomMap.put("addPopedom", addPopedom);
        popedomMap.put("deletePopedom", deletePopedom);
        return popedomMap;

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult<GetResult> batchRoleAudit(HttpServletRequest request, RoleAuditBO auditBO) throws Exception {
        String[] auditIds = auditBO.getAuditId().split(",");
        for (String auditId : auditIds) {
            RoleAuditBO roleAuditBO = new RoleAuditBO();
            BeanUtil.copyProperties(auditBO, roleAuditBO);
            roleAuditBO.setAuditId(auditId);
            BaseResult result = roleAudit(request, roleAuditBO);
            if (!"00".equals(result.getDataCode())) {
                return GetResult.getResultFail(result.getDataMessage());
            }
        }
        return GetResult.getResultSuccess("审核成功");
    }

    /**
     * @Description: 根据机构码获取子机构码列表
     * @Author: jiy.fang
     * @Date: 2019/7/19 15:18
     */
    private List<String> getListOrgIds(String orgId) {
        String strkey = "orgid:" + orgId;
        List<String> lists = null;
        lists = redisUtils.get(strkey, List.class);
        if (lists == null) {
            lists = new ArrayList<>();
            recursiveGetOrgId(lists, orgId);
            redisUtils.set(strkey, lists);
        }
        return lists;
    }

    //递归查询子机构
    private void recursiveGetOrgId(List<String> lists, String orgId) {
        List<String> orgIdList = organizationMapper.getOrgIdsList(orgId);
        while (orgIdList.isEmpty()) {
            return;
        }

        orgIdList.forEach(childOrgId -> {
            lists.add(childOrgId);
            recursiveGetOrgId(lists, childOrgId);
        });
    }

    /**
     * 角色权限修改--审核通过后，下属用户被迫登出
     */
    private void disableLogout(Operator operator) {
        RedisUtil.del("login:operator:" + operator.getOpName());
        RedisUtil.del("popedom:loginOperator:" + operator.getOrgId() + "&" + operator.getRoleId());
        log.info("用户被停用，已登出");
    }

    private void addRolePopedom(Role role, RoleCopy roleCopy) {
        //获取最新分配的权限
        List<RolePopedom> newRolePopedomList = popedomMapper.findTepRolePopedomListByRoleId(role.getRoleId(),
                roleCopy.getAuditId());
        //更新角色权限表
        if (!newRolePopedomList.isEmpty()) {
            popedomMapper.insertRolePopedom(newRolePopedomList);
        }
        log.info("角色权限分配通过审核，审核编号={}，机构编号={}", roleCopy.getAuditId(), roleCopy.getOrgId());
        //获取该角色下所属权限,并被迫登出
        List<Operator> operatorList = operatorMapper.getListOperatorByroleId(roleCopy.getRoleId());
        for (Operator operator1 : operatorList) {
            disableLogout(operator1);
        }
    }
}
